/**
 * ***************************************
 * @file ymodem.h
 * @author : {Lek} (emimand1010@gmail.com)
 * @brief : 
 * @version 0.1
 * @date : 2024-11-23
 * @copyright Copyright (c) 2024
 * 
 * ***************************************
 */
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "usbat.h"

// #define Ymodem_Printf   lUSB_printf
#define Ymodem_Malloc pvPortMalloc
#define Ymodem_Free vPortFree

/* SOH/STX + 序列号 + 有效负载 + CRC 校验和 */
#define _RYM_SOH_PKG_SZ (1 + 2 + 128 + 2)  // SOH 包大小
#define _RYM_STX_PKG_SZ (1 + 2 + 1024 + 2) // STX 包大小
/* RYM 错误码
 *
 添加自己的错误码。
 */
/* 握手超时 */
#define RYM_ERR_TMO 0x70
/* 错误的操作码，错误的 SOH、STX 等 */
#define RYM_ERR_CODE 0x71
/* 错误的序列号 */
#define RYM_ERR_SEQ 0x72
/* 错误的 CRC 校验和 */
#define RYM_ERR_CRC 0x73
/* 接收到的数据不足 */
#define RYM_ERR_DSZ 0x74
/* 用户中止传输 */
#define RYM_ERR_CAN 0x75
/* 错误的应答，错误的 ACK 或 C */
#define RYM_ERR_ACK 0x76
/* 文件无效传输 */
#define RYM_ERR_FILE 0x77
/* 开辟空间内存不足 */
#define RYM_ENOMEM 0x78

#define RYM_OK 0x00

/* 当用户主动结束会话时发送的 CAN 数量 */
#ifndef RYM_END_SESSION_SEND_CAN_NUM
#define RYM_END_SESSION_SEND_CAN_NUM 0x07
#endif

/* 两次握手操作码之间的间隔时长（以 tick 为单位） */
#ifndef RYM_CHD_INTV_TICK
#define RYM_CHD_INTV_TICK (200)
#endif

/* 传输超时时间*/
#ifndef RYM_TRANTIMEROUT
#define RYM_TRANTIMEROUT (200)
#endif

/* 接收握手超时时间（以 s 为单位） */
#ifndef RYM_READHANDSHAKE
#define RYM_READHANDSHAKE (30)
#endif

/* 发送握手超时时间（以 s 为单位） */
#ifndef RYM_SENDHANDSHAKE
#define RYM_SENDHANDSHAKE (30)
#endif

/* 中间错误包 重发次数*/
#ifndef RYM_ERRPACKNUM
#define RYM_ERRPACKNUM (3)
#endif

/* 发送协议数据的规格*/
#ifndef RYM_SENDPACKSPE
#define RYM_SENDPACKSPE (1024)
#endif



enum rym_code
{
    RYM_CODE_NONE = 0x00, // 无操作码
    RYM_CODE_SOH = 0x01,  // 起始数据块标识符（128字节数据块）
    RYM_CODE_STX = 0x02,  // 起始数据块标识符（1024字节数据块）
    RYM_CODE_EOT = 0x04,  // 传输结束标识符
    RYM_CODE_ACK = 0x06,  // 确认信号
    RYM_CODE_NAK = 0x15,  // 否认信号
    RYM_CODE_CAN = 0x18,  // 取消信号
    RYM_CODE_C = 0x43,    // 请求信号
    RYM_CODE_O = 0x4F,    // XHELL 结束信号
};

typedef enum
{
    RYM_STAGE_NONE, // 未知状态
    /* 发送 C 时设置 */
    RYM_STAGE_ESTABLISHING, // 建立阶段
    /* 接收到包0并发送 ACK 和第二个 C 时设置 */
    RYM_STAGE_ESTABLISHED, // 已建立状态
    /* 发送方响应第二个 C 并接收方收到实际数据包时设置 */
    RYM_STAGE_TRANSMITTING, // 传输中状态
    /* 发送方发送 EOT 时设置 */
    RYM_STAGE_FINISHING, // 结束中状态
    /* 传输真正结束时设置，即在 NAK、C、最终空包后 */
    RYM_STAGE_FINISHED, // 已完成状态
} rym_stage;

struct _RYM_t; // 先前向声明 _RYM_t 结构体

/* 接收文件时，buf 为从 ymodem 协议接收到的数据，len 为数据大小。
 *
 * 发送文件时，len 为 RYM 中的 buf 大小。回调函数需要填充要发送的数据到 buf。
 * 返回 RYM_CODE_EOT 将终止传输，buf 将被丢弃。任何其他返回值将导致传输继续。
 */
typedef enum rym_code (*rym_callback)(struct _RYM_t *ctx, uint8_t *buf, uint32_t len);

typedef struct _RYM_t
{
    rym_callback on_data;  // 数据处理回调
    rym_callback on_begin; // 开始回调
    rym_callback on_end;   // 结束回调
    /* 发生错误时，用户需检查该变量以获取错误发生的阶段。 */
    rym_stage stage; // 传输阶段
    /* 用户可通过该变量获取错误内容 */
    uint8_t *buf; // 缓存区
    // uint8_t ucFilename[125];
    // uint32_t ulFileSize;

} RYM_t;

int RYM_SendFile(RYM_t *pxRYM_Ag,
                 rym_callback on_begin,
                 rym_callback on_data,
                 rym_callback on_end);
                 
int RYM_ReadFile(RYM_t *pxRYM_Ag,
                 rym_callback on_begin,
                 rym_callback on_data,
                 rym_callback on_end);
